#include "configmanage.h"
#include <QFile>
#include <QDebug>
#include <QJsonParseError>
#include <QCryptographicHash>
#include <QProcess>
#include <QJsonArray>
#include <QCoreApplication>
#include <QSettings>
#include <openssl/ssl.h>
#include <openssl/aes.h>

#define PRODUCT_SN_INI              "/opt/ota/.osdaemon_ini"
#define PRODUCT_SN_CONFIG           "/opt/ota/.osdaemon_config"
#define PRODUCT_VERSION_FILE        "/opt/ota/.osdaemon_ver"
#define PRODUCT_TIPTIME_FILE        "/opt/ota/.osdaemon_tip"
#define PRODUCT_AUTO_UPGRADE_FILE   "/opt/ota/.update_status.ini"
#define PRODUCT_UPGRADE_TASK_FILE   "/opt/ota/.osdaemon_task"
#define SDDM_INI_SDDM_LOCALINFO     "/etc/.sddmLocalInfo.ini"
// new add
#define PRODUCT_UPDATEING_FILE      "/opt/ota/.osdaemon_tasks"
#define PRODUCT_HOSTNAME_FILE       "/opt/ota/.osdaemon_host"
//esport box
#ifdef ESPORT_BOX

#define PRODUCT_INFO_FILE           "/opt/config/.device_info"

#else

#define PRODUCT_INFO_FILE           "/etc/.sddmd"

#endif

#define REGIST_RESULT_FILE          "/opt/config/.regist_result"

#ifdef DEV_DATA
#define PRODUCT_KET        "20765968200368129" 
#define PRODUCT_SECRET     "NGUzMjMzMzItNjI4YS00NTMzLWJhYWQtYWMzMTFjMzM2NDQy"
#endif
#define DEVICE_NAME        "DeviceName"

#ifdef CLOUD_IP_ADDR
#define HOSTNAME           "192.168.0.12"
#define PORT_RGISTER       (30883)
#define PORT_DAEMON        (31883)
#else
#define HOSTNAME           "10.0.0.138"
#define PORT_RGISTER       (10883)
#define PORT_DAEMON        (11883)
#endif

namespace Cryptogram {
QString     GenerateSN(const QString& id);
int         base64_encode(char *in, int len, char *out);
int         getPKCS7PaddedLength(int dataLen, int alignSize);
QByteArray  PKCS7Padding(const QByteArray &in, int alignSize);
QByteArray  PKCS7UnPadding(const QByteArray &in);
bool        ecb_encrypt(const QByteArray &in, QByteArray &out, const QByteArray &key, bool enc);
int         strSplitPoint(QString str);
bool        strComparePoint(QString str, QString tmp);
}

ConfigManage::ConfigManage(QObject *parent)
    : QObject{parent}
{
    
}

bool ConfigManage::init()
{
    if(!(readSddmd() && readVersion() && readTip() && readAutoUpdate() && readSNCode() && readHost())){
        qDebug() << "ConfigManage::init() error !!!!!!!";
        //exit(-1);
        return false;
    }
#ifdef OLD_DATE
    m_productSalt = Cryptogram::GenerateSN(m_deviceId);
    qDebug() << "product salt: " << m_productSalt;
    QString in = m_productKey + "+" + m_deviceId + "+" + QString::number(m_deviceNode) + "+" + m_productSalt;
    qDebug() << "product info: " << in;
    QByteArray out;
    if(!Cryptogram::ecb_encrypt(in.toLatin1(), out, m_productScrent.toLatin1(), true))
    {
        qDebug() << "secret product info error";
        return false;
    }
    m_secret_outBase64 = QString(out.toBase64());
#endif
    qDebug()<<"> read files information Initialization finished!";

    return true;
}

void ConfigManage::wirteUpdateLoadingFlag(UpdateFlag flag)
{
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    config.setValue("UpdateFlag/flag",static_cast<int>(flag));
}

bool ConfigManage::isExistBreakOff()
{
    if(!QFile::exists(QString(PRODUCT_UPDATEING_FILE))){
        return false;
    }
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    UpdateFlag flag = static_cast<UpdateFlag>(config.value("UpdateFlag/flag",static_cast<int>(UpdateFlag::UF_UpdateComplete)).toInt());
    
    return (flag != UpdateFlag::UF_UpdateComplete);
}

bool ConfigManage::writeUpdatePackageDate(const QList<QJsonObject> pckList)
{
    if(pckList.size()<=0)
        return false;
    QJsonArray jsarray;
    for(auto& jsobj:pckList){
        jsarray.append(jsobj);
    }
    QJsonDocument doc(jsarray);
    QByteArray bytearray = doc.toJson(QJsonDocument::Compact);
    
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    config.setValue("UpdatePackages/jsArray",bytearray);
    config.sync();
    return true;
}

bool ConfigManage::writeUpdatePackageDate_null()
{
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    return true;
}

bool ConfigManage::readBreakOffDate(QList<QJsonObject> &pckList)
{
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    if(!config.contains("UpdatePackages/jsArray")){    
        return false;
    }
    QByteArray readArray = config.value("UpdatePackages/jsArray").toByteArray();
    
    QJsonDocument readDoc = QJsonDocument::fromJson(readArray);
    
    if(readDoc.isEmpty() || !readDoc.isArray()){
        return false;
    }
    QJsonArray jsarray = readDoc.array();
    pckList.clear();
    for(int i=0;i<jsarray.size();++i){
        pckList.append(jsarray.at(i).toObject());
    }
    return true;
}

bool ConfigManage::delUpatePackageDate()
{
    QSettings config(QString(PRODUCT_UPDATEING_FILE),QSettings::NativeFormat);
    if(!config.contains("UpdatePackages/jsArray")){
        return true;
    }
    config.remove("UpdatePackages/jsArray");
    return true;
}

void ConfigManage::writeSDDMRegister(bool falg)
{
    QSettings config(SDDM_INI_SDDM_LOCALINFO,QSettings::IniFormat);
    config.setValue("LOCALINFO/deviceRegister_status",falg);
}

void ConfigManage::writeNewVersion(QString version, QString model)
{
    if(version.isEmpty() || model.isEmpty()){
        qDebug()<<"> writeNewVersion() date is empty.";
        return;
    }
    //使用正则表达式去除所有数字前的零
    
    m_productVersion = removeLeadingZeros(version);
    m_productModule = model;
    QFile file(PRODUCT_VERSION_FILE);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text))
    {
        qDebug() << "open file failed: " << file.fileName() << file.errorString();
        return;
    }
    QTextStream astream(&file);
    astream << m_productVersion << "&" << m_productModule;
    file.close();
    return;
}

bool ConfigManage::readHost()
{
    //http
    QString bind = "http://api.needleos.com/os_user/e_sport_box/check";
    QString macip = "http://rest.cloud.needleos.net/admin/device/update";
    QSettings host(QString(PRODUCT_HOSTNAME_FILE),QSettings::NativeFormat);
    //默认填入正式环境地址
    if(!QFile::exists(QString(PRODUCT_HOSTNAME_FILE))){
        host.setValue("HostAddr/hostname",QString(HOSTNAME));
        host.setValue("HostAddr/protregister",PORT_RGISTER);
        host.setValue("HostAddr/protdaemon",PORT_DAEMON);
        host.setValue("HostAddr/devicename",QString(DEVICE_NAME));
        //http
        host.setValue("Http/bindAgent",bind);
        host.setValue("Http/macIP",macip);
        //download timeout
        host.setValue("Timeout/time",5*60);
    }
    m_hostname = host.value("HostAddr/hostname",QString(HOSTNAME)).toString();
    m_portRegister = host.value("HostAddr/protregister",QString(PORT_RGISTER)).toInt();
    m_portDaemon =  host.value("HostAddr/protdaemon",QString(PORT_DAEMON)).toInt();
    m_devicename = host.value("HostAddr/devicename",QString(DEVICE_NAME)).toString();
    //http
    m_urlBindAgent = host.value("Http/bindAgent",bind).toString();
    m_urlMacIP = host.value("Http/macIP",macip).toString();
    //timeout
    m_timeout = host.value("Timeout/time",5*60).toULongLong();
    return true;
}

void ConfigManage::writeEsportBoxBindAgent(bool isBindAgent,bool isAlreadyRegist)
{
    //设备认证信息记录本地
    QFile file(REGIST_RESULT_FILE);
    if(file.open(QIODevice::WriteOnly)){
        QJsonObject obj;
        obj.insert("regist", isAlreadyRegist);
        obj.insert("agent", isBindAgent);
        QJsonDocument doc(obj);
        file.write(doc.toJson());
        file.close();
    }else{
        qDebug() << "write regist result error";
    }
}

QString ConfigManage::removeLeadingZeros(const QString &str)
{
    // 去除前置的0
    QString result = str;
    result.remove(QRegularExpression("^0+|(?<=\\.)0+"));
    QStringList list = result.split('.');
    for(int i = 0;i < list.size();i++){
        if(list[i].isEmpty()){
            list[i].append('0');
        }
    }
    return list.join('.');
}

bool ConfigManage::readSddmd()
{
    // 产品信息
    QFile file(PRODUCT_INFO_FILE);
    if(!file.open(QIODevice::ReadOnly)){
        qDebug() << "open file error:" << file.fileName();
        return false;
    }
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
    file.close();
    if(!doc.isNull() && (error.error == QJsonParseError::NoError))
    {
        QJsonObject obj = doc.object();
#ifdef DEV_DATA
        m_productKey = QString(PRODUCT_KET);
        m_productScrent = QString(PRODUCT_SECRET);
#else
        m_productKey = obj.value(QLatin1String("productKey")).toString();
        m_productScrent = obj.value(QLatin1String("productSecret")).toString();
#endif
    }
    else{
        qDebug() << file.fileName() << " json error";
        return false;
    }
    qDebug() << "productKey:" << m_productKey;
    qDebug() << "productSecret:" << m_productScrent;
    return true;
}

bool ConfigManage::readVersion()
{
    // 版本信息
    QFile file1(PRODUCT_VERSION_FILE);
    if(file1.exists()){
        if(!file1.open(QIODevice::ReadOnly)){
            qDebug() << "open file error:" << file1.fileName();
            return false;
        }
        QString line = file1.readLine();
        file1.close();
        
        if(line.endsWith('\n'))
            line.chop(1);
        
        qDebug() << PRODUCT_VERSION_FILE <<", line:" << line;
        
        QStringList list = line.split("&");
        qDebug() << "list.size():" << list.size();
        if(list.size() >= 2)
        {
            m_productVersion = list[0];
            m_productModule = list[1];
        }
        else {
            qDebug() << "read" << PRODUCT_VERSION_FILE << "error";
            return false;
        }
        
    }
    qDebug() << "productVersion:" << m_productVersion << "productModule:" << m_productModule;
    return true;
}

bool ConfigManage::readTip()
{
    // 提醒升级开关
    QJsonParseError error;
    QJsonDocument doc;
    QFile file2(PRODUCT_TIPTIME_FILE);
    if(file2.exists()){
        if(!file2.open(QIODevice::ReadOnly)){
            qDebug() << "open file error:" << file2.fileName();
            return false;
        }
        doc = QJsonDocument::fromJson(file2.readAll(), &error);
        file2.close();
        if(!doc.isNull() && (error.error == QJsonParseError::NoError))
        {
            QJsonObject obj = doc.object();
            m_tipTimeStatus = obj.value(QLatin1String("tipstatus")).toInt();
            if(m_tipTimeStatus == 2){
                QString time = obj.value(QLatin1String("tiptime")).toString();
                m_tipTime = QDateTime::fromString(time, "yyyy-MM-dd hh:mm:ss");
            }
        }
        else{
            qDebug() << file2.fileName() << " json error";
        }
    }
    return true;
}

bool ConfigManage::readAutoUpdate()
{
    // 用户自动升级开关
    QJsonParseError error;
    QJsonDocument doc;
    QFile file3(PRODUCT_AUTO_UPGRADE_FILE);
    if(file3.exists()){
        if(!file3.open(QIODevice::ReadOnly)){
            qDebug() << "open file error:" << file3.fileName();
            return false;
        }
        doc = QJsonDocument::fromJson(file3.readAll(), &error);
        file3.close();
        if(!doc.isNull() && (error.error == QJsonParseError::NoError))
        {
            QJsonObject obj = doc.object();
            QString str = obj.value("auto_update").toString();
            if(str == "true")
            {
                m_autoUpgrade = true;
            }else{
                m_autoUpgrade = false;
            }
        }
        else{
            qDebug() << file3.fileName() << " json error";
        }
    }
    qDebug()<<"> ConfigManage::readAutoUpdate() auto update:"<<m_autoUpgrade;
    return true;    
}

bool ConfigManage::readSNCode()
{
    QProcess p;
    QString cmd = "dmidecode -t 1 | grep \"Serial Number\" | awk \'{print $3}\'";           // 先查系统命令
    qDebug() << "查询SN cmd: " << cmd;
    p.start("bash", QStringList() << "-c" << cmd);
    p.waitForFinished(10*1000);
    QString sn = p.readAllStandardOutput().simplified();
    //QString sn;
    sn.remove("\n");
    qDebug()<<"> cmd sn:"<<sn;
    if(sn.isEmpty() || sn=="Default")
    {
        qDebug() << "Get dm sn failed";
#ifdef ESPORT_BOX
        // 产品信息
        QFile file(PRODUCT_INFO_FILE);
#else
        // 产品信息
        QFile file(PRODUCT_SN_INI);                                                         // 查不到，再查配置文件
#endif
        if(!file.open(QIODevice::ReadOnly)){
            qDebug() << "open file error:" << file.fileName();
            return false;
        }
        QJsonParseError error;
        QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
        file.close();
        if(!doc.isNull() && (error.error == QJsonParseError::NoError))
        {
            QJsonObject obj = doc.object();
            sn = obj.value(QLatin1String("sn")).toString();
            if(sn.isEmpty())
            {
                qDebug() << "Get ini sn failed";
                return false;
            }
        }
        else{
            qDebug() << file.fileName() << " json error";
            return false;
        }
    }
    
    m_deviceId = sn;
    qDebug() << "Serial Number:" << m_deviceId;
    
    // 保存SN到文件
    QFile file(PRODUCT_SN_CONFIG);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text))
    {
        qDebug() << "open file failed: " << file.fileName();
        return false;
    }
    QJsonObject d;
    d.insert("sn", m_deviceId);
    QJsonDocument doc(d);
    QTextStream astream(&file);
    astream << doc.toJson();
    file.close();
    
    return true;
}

bool ConfigManage::readTasks()
{
    qDebug() << __FUNCTION__ << "---";
    // 是否有升级任务
    QFile file(PRODUCT_UPGRADE_TASK_FILE);
    if(!file.exists()){
        qDebug() << "no taskfile ---";
        return true;
    }
    if(!file.open(QIODevice::ReadOnly)){
        qDebug() << "open file error:" << file.fileName();
        return false;
    }
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
    file.close();
    if(!doc.isNull() && (error.error == QJsonParseError::NoError))
    {
        if(doc.isArray())
        {
            QJsonArray arr = doc.array();
            for(int i=0; i < arr.count(); i++)
            {
                QJsonObject jsobj = arr.at(i).toObject();
                m_updatePackageList.append(jsobj);
            }
        }
    }
    if(m_updatePackageList.isEmpty()){
        qDebug() << "pakgList isEmpty, taskfile error, remove:" << PRODUCT_UPGRADE_TASK_FILE;
        QFile::remove(PRODUCT_UPGRADE_TASK_FILE);
        return false;
    }
    return true;
}

int ConfigManage::portDaemon() const
{
    return m_portDaemon;
}

void ConfigManage::setPortDaemon(int newPortDaemon)
{
    m_portDaemon = newPortDaemon;
}

QString ConfigManage::urlBindAgent() const
{
    return m_urlBindAgent;
}

QString ConfigManage::urlMacIP() const
{
    return m_urlMacIP;
}

quint64 ConfigManage::timeout() const
{
    return m_timeout;
}

int ConfigManage::portRegister() const
{
    return m_portRegister;
}

void ConfigManage::setPortRegister(int newPortRegister)
{
    m_portRegister = newPortRegister;
}

QString ConfigManage::devicename() const
{
    return m_devicename;
}

void ConfigManage::setDevicename(const QString &newDevicename)
{
    m_devicename = newDevicename;
}

QString ConfigManage::hostname() const
{
    return m_hostname;
}

void ConfigManage::setHostname(const QString &newHostname)
{
    m_hostname = newHostname;
}

void ConfigManage::onTipstatus(int flag)
{
    qDebug() << __FUNCTION__ << "m_tipTimeStatus:" << m_tipTimeStatus << ", flag:" << flag;
    //TODO 
    //if(m_tipTimeStatus != flag)
    //{
    m_tipTimeStatus = flag;
    //tipTime_ = QDateTime::currentDateTime();
    setTipTime(QDateTime::currentDateTime());
    QString timestr = tipTime().toString("yyyy-MM-dd hh:mm:ss");
    
    QFile file(PRODUCT_TIPTIME_FILE);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Text))
    {
        qDebug() << "open file failed: " << file.fileName();
        return ;
    }
    
    QJsonObject obj;
    obj.insert("tipstatus", m_tipTimeStatus);
    obj.insert("tiptime", timestr);
    QJsonDocument doc(obj);
    QTextStream astream(&file);
    astream << doc.toJson();
    file.close();
    
    qDebug() << __FUNCTION__ << "update tipTimeStatus";
    return ;
    //}
}

void ConfigManage::onReadWallpaper(QString user)
{
    QString path = QString("/home/%1/.config/plasma-org.kde.plasma.desktop-appletsrc").arg(user);
    QFile file(path);
    if(!file.open(QIODevice::ReadOnly)){
        qDebug()<<"ConfigManage::onReadWallpaper() file open fail!";
        return;
    }
    QByteArray dataArray;
    do{
        dataArray = file.readLine();
        QString test(dataArray);
        if(test.contains("[Containments][40][Wallpaper][org.kde.image][General]")){
            do{
                dataArray = file.readLine();
                QString valuePath(dataArray);
                if(valuePath.contains("Image")){
                    QStringList list = valuePath.split("=");
                    QString wallpaper = list.last().remove("\n");
                    qDebug()<<"> ConfigManage::onReadWallpaper() wallpaper path:"<<wallpaper;
                    emit sigUserWallpaperPath(wallpaper);
                    file.close();
                    return;
                }
            }while(!dataArray.isEmpty());
        }
    }while(!dataArray.isEmpty());
    file.close();
}

void ConfigManage::onWriteQRCodeUrl(QJsonObject jsobj)
{
    if(jsobj.contains("code")){
        int code = jsobj.value("code").toInt();
        if(!code && jsobj.contains("data")){
            QJsonObject jsData= jsobj.value("data").toObject();
            QString data = jsData.value("config").toString();
            QFile file(PRODUCT_INFO_FILE);
            if(!file.open(QIODevice::ReadOnly)){
                qDebug()<<"onWriteQRCodeUrl() only read open file error!";
                return;
            }
            QJsonDocument jsDoc = QJsonDocument::fromJson(file.readAll());
            QJsonObject jsObj = jsDoc.object();
            file.close();
            jsObj.insert("QRCodeUrl",data);
            QJsonDocument jswriteobj(jsObj);
            QByteArray array = jswriteobj.toJson();
            
            if(!file.open(QIODevice::Truncate | QIODevice::WriteOnly)){
                qDebug()<<"onWriteQRCodeUrl() only write open file error!";
                return;
            }
            
            file.write(array);
            file.close();
            return;
        }
    }
    qDebug()<<"> onWriteQRCodeUrl() error msg:"<<jsobj.value("msg").toString();
}

int ConfigManage::deviceNode() const
{
    return m_deviceNode;
}

void ConfigManage::setDeviceNode(int newDeviceNode)
{
    m_deviceNode = newDeviceNode;
}

QString ConfigManage::productSalt() const
{
    return m_productSalt;
}

void ConfigManage::setProductSalt(const QString &newProductSalt)
{
    m_productSalt = newProductSalt;
}

QString ConfigManage::secret_outBase64() const
{
    return m_secret_outBase64;
}

void ConfigManage::setSecret_outBase64(const QString &newSecret_outBase64)
{
    m_secret_outBase64 = newSecret_outBase64;
}

QList<QJsonObject> ConfigManage::updatePackageList() const
{
    return m_updatePackageList;
}

void ConfigManage::setUpdatePackageList(const QList<QJsonObject> &newUpdatePackageList)
{
    m_updatePackageList = newUpdatePackageList;
}

bool ConfigManage::autoUpgrade() const
{
    return m_autoUpgrade;
}

void ConfigManage::setAutoUpgrade(bool newAutoUpgrade)
{
    m_autoUpgrade = newAutoUpgrade;
}

QDateTime ConfigManage::tipTime() const
{
    return m_tipTime;
}

void ConfigManage::setTipTime(const QDateTime &newTipTime)
{
    m_tipTime = newTipTime;
}

int ConfigManage::tipTimeStatus() const
{
    return m_tipTimeStatus;
}

void ConfigManage::setTipTimeStatus(int newTipTimeStatus)
{
    m_tipTimeStatus = newTipTimeStatus;
}

QString ConfigManage::deviceId() const
{
    return m_deviceId;
}

void ConfigManage::setDeviceId(const QString &newDeviceId)
{
    m_deviceId = newDeviceId;
}

QString ConfigManage::productModule() const
{
    return m_productModule;
}

void ConfigManage::setProductModule(const QString &newProductModule)
{
    m_productModule = newProductModule;
}

QString ConfigManage::productVersion() const
{
    return m_productVersion;
}

void ConfigManage::setProductVersion(const QString &newProductVersion)
{
    m_productVersion = newProductVersion;
}

QString ConfigManage::productScrent() const
{
    return m_productScrent;
}

void ConfigManage::setProductScrent(const QString &newProductScrent)
{
    m_productScrent = newProductScrent;
}

QString ConfigManage::productKey() const
{
    return m_productKey;
}

void ConfigManage::setProductKey(const QString &newProductKey)
{
    m_productKey = newProductKey;
}



namespace Cryptogram{
QString GenerateSN(const QString& id) {
    QCryptographicHash Hash(QCryptographicHash::Md5);
    Hash.addData(id.toLatin1());
    QByteArray md5 = Hash.result();
    return md5.toHex();
}

int base64_encode(char *in, int len, char *out)
{
    qDebug() << "base64 in:" << in;
    
    BIO *b64, *bio;
    BUF_MEM *bptr = NULL;
    
    if(in==NULL){
        return -1;
    }
    
    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);
    
    BIO_write(bio, in, len);
    BIO_flush(bio);
    
    BIO_get_mem_ptr(bio, &bptr);
    memcpy(out, bptr->data, bptr->length);
    out[bptr->length-1] = '\0';
    
    BIO_free_all(bio);
    
    qDebug() << "base64 out:" << out;
    return 0;
}

int getPKCS7PaddedLength(int dataLen, int alignSize)
{
    // 计算填充的字节数（按alignSize字节对齐进行填充）
    int remainder = dataLen % alignSize;
    int paddingSize = (remainder == 0) ? alignSize : (alignSize - remainder);
    return (dataLen + paddingSize);
}

QByteArray PKCS7Padding(const QByteArray &in, int alignSize)
{
    // 计算需要填充字节数（按alignSize字节对齐进行填充）
    int remainder = in.size() % alignSize;
    int paddingSize = (remainder == 0) ? alignSize : (alignSize - remainder);
    
    // 进行填充
    QByteArray temp(in);
    temp.append(paddingSize, paddingSize);
    return temp;
}

QByteArray PKCS7UnPadding(const QByteArray &in)
{
    char paddingSize = in.at(in.size() - 1);
    return in.left(in.size() - paddingSize);
}

bool ecb_encrypt(const QByteArray &in, QByteArray &out, const QByteArray &key, bool enc)
{
    // 检查密钥合法性(只能是16、24、32字节)
    Q_ASSERT(key.size() == 16 || key.size() == 24 || key.size() == 32);
    
    if (enc)
    {
        // 生成加密key
        AES_KEY aes_key;
        if (AES_set_encrypt_key((const unsigned char*)key.data(), key.size() * 8, &aes_key) != 0)
        {
            return false;
        }
        
        // 进行PKCS7Padding填充
        QByteArray inTemp = PKCS7Padding(in, AES_BLOCK_SIZE);
        
        // 执行ECB模式加密
        out.resize(inTemp.size()); // 调整输出buf大小
        for (int i = 0; i < inTemp.size() / AES_BLOCK_SIZE; i++)
        {
            AES_ecb_encrypt((const unsigned char*)inTemp.data() + AES_BLOCK_SIZE * i,
                            (unsigned char*)out.data() + AES_BLOCK_SIZE * i,
                            &aes_key,
                            AES_ENCRYPT);
        }
        return true;
    }
    else
    {
        // 生成解密key
        AES_KEY aes_key;
        if (AES_set_decrypt_key((const unsigned char*)key.data(), key.size() * 8, &aes_key) != 0)
        {
            return false;
        }
        
        // 执行ECB模式解密
        out.resize(in.size()); // 调整输出buf大小
        for (int i = 0; i < in.size() / AES_BLOCK_SIZE; i++)
        {
            AES_ecb_encrypt((const unsigned char*)in.data() + AES_BLOCK_SIZE * i,
                            (unsigned char*)out.data() + AES_BLOCK_SIZE * i,
                            &aes_key,
                            AES_DECRYPT);
        }
        
        // 解除PKCS7Padding填充
        out = PKCS7UnPadding(out);
        
        return true;
    }
}

int strSplitPoint(QString str)
{
    if(str.isEmpty())
        return -1;
    
    QStringList vlist = str.split(".");
    int l = vlist.length();
    int v = 0;
    for(int i=0; i<l; i++){
        v = v*10 + vlist[i].toInt();
    }
    return v;
}

bool strComparePoint(QString str, QString tmp)
{
    if(str.isEmpty())
        return false;
    
    if(tmp.isEmpty())
        return true;
    
    QStringList vlist = str.split(".");
    QStringList tlist = tmp.split(".");
    
    int vlen = vlist.length();  // 4 2.0.0.0
    int tlen = tlist.length();  // 3 2.0.0
    
    bool ret = false;
    if(vlen > tlen)
    {
        ret = true;
    }
    else{
        tlen = vlen;
    }
    
    for(int i=0; i<tlen; i++){
        if(vlist[i].toInt() > tlist[i].toInt())
            return true;
        
        if(vlist[i].toInt() == tlist[i].toInt())
            continue;
        
        if(vlist[i].toInt() < tlist[i].toInt())
            return false;
    }
    
    return ret;
}
}
